package org.EasyDevelop.Builder;

import org.EasyDevelop.Bean.Constants;
import org.EasyDevelop.Bean.FieldInfo;
import org.EasyDevelop.Bean.TableInfo;
import org.EasyDevelop.Utils.DateUtils;
import org.EasyDevelop.Utils.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;

public class PoBuilder {
    private static final Logger logger = LoggerFactory.getLogger(PoBuilder.class);
    public static void execute(TableInfo tableInfo){
        File folder = new File(Constants.PATH_PO);

        if(!folder.exists()) folder.mkdirs();

        File poFile = new File(folder, tableInfo.getBeanName() + Constants.JAVA_SUFFIX);

        OutputStream os = null;
        OutputStreamWriter osw = null;
        BufferedWriter bw = null;

        try {
            os = new FileOutputStream(poFile);
            osw = new OutputStreamWriter(os, "UTF8");
            bw = new BufferedWriter(osw);

            //package
            bw.write("package " + Constants.PACKAGE_PO + ";");
            bw.newLine();
            bw.newLine();

            //import
            bw.write("import java.io.Serializable;");
            bw.newLine();

            //special import
            //date
            if(tableInfo.getHaveDate() || tableInfo.getHaveDateTime()){
                bw.write("import java.util.Date;");
                bw.newLine();
                bw.write("import " + Constants.PACKAGE_UTILS + "." + "DateUtils;");
                bw.newLine();
                bw.write("import " + Constants.PACKAGE_ENTITY + ".baseEnum." + "DateTimePatternEnum;");
                bw.newLine();
            }
            //bigDecimal
            if(tableInfo.getHaveBigDecimal()){
                bw.write("import java.math.BigDecimal;");
                bw.newLine();
            }
            //serializable and deserializable
            if (tableInfo.getHaveDate() || tableInfo.getHaveDateTime()){
                bw.write("import " + Constants.DATE_SERIALIZABLE_CLASS + ";");
                bw.newLine();
                bw.write("import " + Constants.DATE_DESERIALIZABLE_CLASS + ";");
                bw.newLine();
            }
            //json ignore
            if(tableInfo.getHaveIgnoreField()){
                bw.write("import " + Constants.IGNORE_MAP.get("beanToJsonClass") + ";");
                bw.newLine();
            }

            bw.newLine();

            //class comment
            CommentBuilder.createClassComment(bw,tableInfo.getComment());
            //class start
            bw.write("public class " + tableInfo.getBeanName() + " implements Serializable {");
            bw.newLine();


            bw.newLine();
            bw.newLine();
            //no construct
            bw.write("\tpublic " + StringUtils.upperCaseFirstLetter(tableInfo.getBeanName()) + "(");
            bw.write("){");
            bw.newLine();
            bw.write("\t}");

            //all construct
            bw.write("\tpublic " + StringUtils.upperCaseFirstLetter(tableInfo.getBeanName()) + "(");
            for (int i = 0; i < tableInfo.getFieldList().size(); i++) {
                FieldInfo fieldInfo = tableInfo.getFieldList().get(i);
                bw.write(fieldInfo.getJavaType() + " " + StringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()));
                if(i!=tableInfo.getFieldList().size()-1){
                    bw.write(", ");
                }
            }
            bw.write("){");
            bw.newLine();

            for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
                bw.write("\t\tthis." + fieldInfo.getPropertyName() + " = " + fieldInfo.getPropertyName() + ";");
                bw.newLine();
            }
            bw.write("\t}");

            //填充field字段
            for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
                //field comment
                CommentBuilder.createFieldComment(bw, fieldInfo.getComment());

                //field annotation
                if(Constants.JAVA_TYPE_DATE.equals(fieldInfo.getJavaType())){
                    bw.write("\t" + String.format(Constants.DATE_SERIALIZABLE_EXPRESSION, DateUtils.YYYY_MM_DD));
                    bw.newLine();
                    bw.write("\t" + String.format(Constants.DATE_DESERIALIZABLE_EXPRESSION, DateUtils.YYYY_MM_DD));
                    bw.newLine();
                }
                if(ArrayUtils.contains(Constants.IGNORE_MAP.get("beanToJsonFiled").split(","),fieldInfo.getFieldName())){
                    bw.write("\t" + String.format(Constants.IGNORE_MAP.get("beanToJsonExpression"), DateUtils.YYYY_MM_DD));
                    bw.newLine();
                }

                //field
                bw.write("\tprivate " + fieldInfo.getJavaType() + " " + StringUtils.processFiled(
                        null == fieldInfo.getFieldName()?"":fieldInfo.getFieldName()
                        ,false) + ";");
                bw.newLine();
                bw.newLine();
            }

            //method get/set
            for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
                String tempField = StringUtils.upperCaseFirstLetter(fieldInfo.getPropertyName());
                //set()
                bw.write("\tpublic void set" + tempField + "(" + fieldInfo.getJavaType() + " " + fieldInfo.getPropertyName() + "){");
                bw.newLine();

                bw.write("\t\tthis." + fieldInfo.getPropertyName() + " = " + fieldInfo.getPropertyName() + ";");
                bw.newLine();

                bw.write("\t}");
                bw.newLine();
                bw.newLine();

                //get()
                bw.write("\tpublic " + fieldInfo.getJavaType() + " get" + tempField + "(){");
                bw.newLine();

                bw.write("\t\treturn this." + fieldInfo.getPropertyName() + ";");
                bw.newLine();

                bw.write("\t}");
                bw.newLine();
                bw.newLine();
            }

            //method toString
            bw.write("\t@Override");
            bw.newLine();
            bw.write("\tpublic String toString(){");
            bw.newLine();
            bw.write("\t\treturn \"" + tableInfo.getBeanName() + " = {\" + ");
            bw.newLine();

            for (int i = 0; i < tableInfo.getFieldList().size(); i++) {
                bw.write("\t\t\t\t\"");
                if(i != 0){
                    bw.write(",");
                }
                String str = Constants.JAVA_TYPE_DATE.equals(tableInfo.getFieldList().get(i).getJavaType())
                        ?
                        "DateUtils.format(" + "this." + tableInfo.getFieldList().get(i).getPropertyName() + "," + "DateTimePatternEnum.YYYY_MM_DD_HH_MM_SS.getPattern()" + ")"
                        :
                        "this." + tableInfo.getFieldList().get(i).getPropertyName();
                bw.write(
                        tableInfo.getFieldList().get(i).getPropertyName()
                                + "(" + tableInfo.getFieldList().get(i).getComment() + ")"
                                + " = \"" + " + "
                                + str
                                + " + ");
                if(i!=tableInfo.getFieldList().size()-1){
                    bw.newLine();
                }
            }
            bw.newLine();
            bw.write("\t\t\t\"}\";");

            bw.newLine();

            bw.write("\t}");
            bw.newLine();

            bw.write("}");
            bw.flush();

        } catch (Exception e) {
            logger.error("创建PO文件失败,{}",e);
        } finally {
            if(bw!=null)
                try{
                    bw.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            if(osw!=null)
                try{
                    osw.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            if(os!=null)
                try{
                    os.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
        }

    }
}
